// ---------------------------------------------------------------------------------------------------------------------
//   Copyright (c) SRT Solutions 2009. All rights reserved.
// ---------------------------------------------------------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;

namespace SRTSolutions.Elevate.Guide
{
    [TestFixture]
    public class MultiMap
    {
        MultiMap<int, int> multimap;
        [SetUp]
        public void Setup()
        {
            multimap = new MultiMap<int, int>();
        }
        [Test]
        public void IsAILookup()
        {
            Assert.IsInstanceOf<System.Linq.ILookup<int,int>>(multimap);
        }
        [Test]
        public void LetsMeAddDuplicateKys()
        {
            multimap.Add(1, 10);
            multimap.Add(1, 20);
        }
        [Test]
        public void LetsMeIterateAndIGetPairsWithTheSameKey()
        {
            multimap.Add(1, 10);
            multimap.Add(1, 20);
            int x = 0;
            foreach (var item in multimap)
            {
                if (x == 0)
                {
                    Assert.AreEqual(1, item.Key);
                    Assert.AreEqual(10, item.Value);
                }
                if (x == 1)
                {
                    Assert.AreEqual(1, item.Key);
                    Assert.AreEqual(20, item.Value);
                }
                x++;
            }
        }
        [Test]
        public void ContainsKeyWorks()
        {
            multimap.Add(1, 2);
            Assert.IsTrue(multimap.ContainsKey(1));
        }
        [Test]
        public void KeysDoesNotDuplicateKeys()
        {
            multimap.Add(1, 10);
            multimap.Add(1, 20);
            Assert.AreEqual(new[] { 1 }, multimap.Keys);
        }
        [Test]
        public void RemoveRemovesAllKeyedValues()
        {
            multimap.Add(1, 10);
            multimap.Add(1, 20);
            multimap.Remove(1);
            foreach (var item in multimap)
            {
                Assert.Fail("There is nothing to iterate");
            }
        }
        [Test]
        public void TryGetValueGetsAllTheValues()
        {
            multimap.Add(1, 10);
            multimap.Add(1, 20);
            IList<int> values;
            multimap.TryGetValue(1, out values);
            Assert.AreEqual(new[]{10,20}, values);
        }
        [Test]
        public void ValuesIsFlattened()
        {
            multimap.Add(1, 10);
            multimap.Add(1, 20);
            multimap.Add(2, 120);
            multimap.Add(2, 3120);
            multimap.Add(3, 312);
            var expected = new[] { 10, 20, 120, 3120, 312 };
            var actual = multimap.Values;
            Assert.AreEqual(expected, actual);
            
        }
        [Test]
        public void IndexingInGetsAllOfTheItems()
        {
            multimap.Add(1, 10);
            multimap.Add(1, 20);
            multimap.Add(2, 120);
            multimap.Add(2, 3120);
            multimap.Add(3, 312);
            var actual = multimap[1];
            Assert.AreEqual(new[] {10,20 }, actual);
            actual = multimap[2];
            Assert.AreEqual(new[]{120,3120}, actual);
            actual = multimap[3];
            Assert.AreEqual(new[]{312}, actual);
        }
        [Test]
        public void CanSetOneOfTheValuesUsingTwoIndexers()
        {
            multimap.Add(1, 10);
            multimap.Add(1, 20);
            multimap.Add(2, 120);
            multimap.Add(2, 3120);
            multimap.Add(3, 312);
            var actual = multimap[1];
            multimap[1][1] = 30;
            Assert.AreEqual(new[] { 10, 30 }, actual);
        }
        [Test]
        public void ClearClears()
        {
            multimap.Add(1, 10);
            multimap.Add(1, 20);
            multimap.Add(2, 120);
            multimap.Add(2, 3120);
            multimap.Add(3, 312);
            multimap.Clear();
            foreach (var item in multimap)
            {
                Assert.Fail("There is nothing to iterate");
            }
        }
        [Test]
        public void CountCountsKeys()
        {
            multimap.Add(1, 10);
            multimap.Add(1, 20);
            multimap.Add(2, 120);
            multimap.Add(2, 3120);
            multimap.Add(3, 312);
            // I added 5 things, but count says 3!  BY DESIGN
            Assert.AreEqual(3, multimap.Count);
        }
        [Test]
        public void OldSchoolGetEnumeratorWorksToo()
        {
            multimap.Add(1, 10);
            System.Collections.IEnumerable old = multimap;
            foreach (KeyValuePair<int,int> item in old)
            {
                Assert.AreEqual(1,item.Key);
                Assert.AreEqual(10, item.Value);
            }
        }
        [Test]
        public void IsAIEnumerableOfKVP()
        {
            multimap.Add(1, 10);
            IEnumerable<KeyValuePair<int, int>> old = multimap;
            foreach (var item in old)
            {
                Assert.AreEqual(1, item.Key);
                Assert.AreEqual(10, item.Value);
            }
        }
        [Test]
        public void IteratesLikeALookup()
        {
            multimap.Add(1, 10);
            multimap.Add(1, 20);
            multimap.Add(2, 120);
            multimap.Add(2, 3120);
            multimap.Add(3, 312);
            ILookup<int, int> lookup = multimap;
            
            var enumer = lookup.GetEnumerator();
            enumer.MoveNext();
            var actual = enumer.Current.Key;
            Assert.AreEqual(1, actual);
            var actual2 = enumer.Current.ToArray();
            Assert.AreEqual(new[]{10,20}, actual2);
            
            enumer.MoveNext();
            actual = enumer.Current.Key;
            Assert.AreEqual(2, actual);
            actual2 = enumer.Current.ToArray();
            Assert.AreEqual(new[] { 120, 3120 }, actual2);

            enumer.MoveNext();
            actual = enumer.Current.Key;
            Assert.AreEqual(3, actual);
            actual2 = enumer.Current.ToArray();
            Assert.AreEqual(new[] { 312 }, actual2);
            
        }
    }
}
